/*
 * Galaxium Messenger
 * Copyright (C) 2008 Paul Burton <paulburton89@gmail.com>
 * 
 * License: GNU General Public License (GPL)
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the Free
 * Software Foundation; either version 2 of the License, or (at your option)
 * any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Net;
using System.Xml;

using Anculus.Core;

using Galaxium.Core;

namespace Galaxium.Protocol.Msn
{
	public static class MsnActivityUtility
	{
		const string _urlBase = "http://appdirectory.messenger.msn.com/AppDirectory/AppDirectory.asmx?op=GetFilteredDataSet2&locale=";
		
		static bool _initialized;
		
		static Uri _uri = null;
		static uint _reqTimer = 0;
		
		static Dictionary<long, List<MsnActivityEntry>> _activities = new Dictionary<long, List<MsnActivityEntry>> ();
		static Dictionary<long, MsnActivityCategory> _categories = new Dictionary<long, MsnActivityCategory> ();
		
		public static Dictionary<long, List<MsnActivityEntry>> Activities
		{
			get { return _activities; }
		}
		
		public static void Initialize ()
		{
			if (_initialized)
				return;

			string lang = CultureInfo.CurrentCulture != null ?
				          CultureInfo.CurrentCulture.TwoLetterISOLanguageName.ToLower () : "en";

			string region = RegionInfo.CurrentRegion != null ?
				            RegionInfo.CurrentRegion.TwoLetterISORegionName.ToLower () : "gb";
			
			_uri = new Uri (string.Format ("{0}{1}-{2}", _urlBase, lang, region));
			_initialized = true;
			
			Request ();
		}
		
		static void Request ()
		{
			Log.Debug ("Requesting from {0}", _uri);
			
			_activities.Clear ();
			_categories.Clear ();
			
			WebClient client = new WebClient ();
			client.DownloadDataCompleted += DataDownloaded;
			client.DownloadDataAsync (_uri);
		}
		
		static void DataDownloaded (object sender, DownloadDataCompletedEventArgs args)
		{
			if (args.Cancelled)
			{
				Log.Warn ("Cancelled");
				RetryRequest ();
				return;
			}
			
			if (args.Error != null)
			{
				Log.Warn (args.Error, "Error downloading activity list");
				RetryRequest ();
				return;
			}
			
			MemoryStream stream = new MemoryStream (args.Result);
			XmlDocument xml = new XmlDocument ();
			xml.Load (stream);
			stream.Dispose ();
			
			LoadActivities (xml.DocumentElement);
		}
		
		static void RetryRequest ()
		{
			if (_reqTimer != 0)
				return;
			
			_reqTimer = TimerUtility.RequestCallback (delegate
			{
				_reqTimer = 0;
				Request ();
			}, 10000);
		}
		
		static void LoadActivities (XmlElement xml)
		{
			if (xml.LocalName != "AppDir")
			{
				Log.Error ("Invalid XML element '{0}'", xml.Name);
				return;
			}
			
			foreach (XmlElement child in xml)
			{
				if (child.LocalName == "Entry")
					LoadActivityEntry (child);
				else if (child.LocalName == "Category")
					LoadActivityCategory (child);
			}
			
			/*foreach (long categoryID in _categories.Keys)
			{
				Log.Debug ("Category {0}: '{1}'", categoryID, _categories[categoryID].Name);
				
				if (!_activities.ContainsKey (categoryID))
					continue;
				
				foreach (MsnActivityEntry entry in _activities[categoryID])
					Log.Debug ("\tEntry {0}: '{1}' '{2}' (ActiveX {3})", entry.ID, entry.Name, entry.Description, entry.ActiveX);
			}*/
		}
		
		static void LoadActivityEntry (XmlElement xml)
		{
			MsnActivityEntry entry = new MsnActivityEntry ();
			
			foreach (XmlElement child in xml)
			{
				if (child.LocalName == "EntryID")
					entry.ID = long.Parse (child.InnerText);
				else if (child.LocalName == "SubscriptionURL")
					entry.SubscriptionUrl = child.InnerText;
				else if (child.LocalName == "Error")
					entry.Error = child.InnerText;
				else if (child.LocalName == "Locale")
					entry.Locale = child.InnerText;
				else if (child.LocalName == "Kids")
					entry.Kids = int.Parse (child.InnerText);
				else if (child.LocalName == "Page")
					entry.Page = int.Parse (child.InnerText);
				else if (child.LocalName == "CategoryID")
					entry.CategoryID = long.Parse (child.InnerText);
				else if (child.LocalName == "Sequence")
					entry.Sequence = long.Parse (child.InnerText);
				else if (child.LocalName == "Name")
					entry.Name = child.InnerText;
				else if (child.LocalName == "Description")
					entry.Description = child.InnerText;
				else if (child.LocalName == "URL")
					entry.Url = child.InnerText;
				else if (child.LocalName == "IconURL")
					entry.IconUrl = child.InnerText;
				else if (child.LocalName == "AppIconURL")
					entry.AppIconUrl = child.InnerText;
				else if (child.LocalName == "PassportSiteID")
					entry.PassportSiteID = long.Parse (child.InnerText);
				else if (child.LocalName == "Type")
					entry.Type = child.InnerText;
				else if (child.LocalName == "Height")
					entry.Height = int.Parse (child.InnerText);
				else if (child.LocalName == "Width")
					entry.Width = int.Parse (child.InnerText);
				else if (child.LocalName == "Location")
					entry.Location = child.InnerText;
				else if (child.LocalName == "MinUsers")
					entry.MinUsers = int.Parse (child.InnerText);
				else if (child.LocalName == "MaxUsers")
					entry.MaxUsers = int.Parse (child.InnerText);
				else if (child.LocalName == "EnableIP")
					entry.EnableIP = bool.Parse (child.InnerText);
				else if (child.LocalName == "ActiveX")
					entry.ActiveX = bool.Parse (child.InnerText);
				else if (child.LocalName == "SendFile")
					entry.SendFile = bool.Parse (child.InnerText);
				else if (child.LocalName == "SendIM")
					entry.SendIM = bool.Parse (child.InnerText);
				else if (child.LocalName == "ReceiveIM")
					entry.ReceiveIM = bool.Parse (child.InnerText);
				else if (child.LocalName == "ReplaceIM")
					entry.ReplaceIM = bool.Parse (child.InnerText);
				else if (child.LocalName == "Windows")
					entry.Windows = bool.Parse (child.InnerText);
				else if (child.LocalName == "MaxPacketRate")
					entry.MaxPacketRate = int.Parse (child.InnerText);
				else if (child.LocalName == "UserProperties")
					entry.UserProperties = bool.Parse (child.InnerText);
				else if (child.LocalName == "ClientVersion")
					entry.ClientVersion = new Version (child.InnerText);
				else if (child.LocalName == "AppType")
					entry.AppType = int.Parse (child.InnerText);
				else if (child.LocalName == "Hidden")
					entry.Hidden = bool.Parse (child.InnerText);
			}
			
			if (!_activities.ContainsKey (entry.CategoryID))
				_activities.Add (entry.CategoryID, new List<MsnActivityEntry> ());
			
			_activities[entry.CategoryID].Add (entry);
		}
		
		static void LoadActivityCategory (XmlElement xml)
		{
			MsnActivityCategory category = new MsnActivityCategory ();
			
			foreach (XmlElement child in xml)
			{
				if (child.LocalName == "CategoryID")
					category.ID = long.Parse (child.InnerText);
				else if (child.LocalName == "Locale")
					category.Locale = child.InnerText;
				else if (child.LocalName == "CategoryIconURL")
					category.IconURL = child.InnerText;
				else if (child.LocalName == "CategoryName")
					category.Name = child.InnerText;
				else if (child.LocalName == "CategoryDescription")
					category.Description = child.InnerText;
			}
			
			_categories[category.ID] = category;
		}
	}
}
